﻿using CommonlyUtils;
using ImClientApi.Utils;
using ImModels.Service.Models.Data;
using ImModels.View;
using ImModels.View.MsgJson;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using xl.webapi.sqlsugar_helper.Entities;

namespace ImClientApi.Controllers
{
    /// <summary>
    /// 消息相关控制器
    /// </summary>
    public class MsgController : BaseAuthController
    {
        /// <summary>
        /// 查询聊天记录
        /// </summary>
        /// <param name="reqview"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<ResView<List<MsgQueryRes>>> QueryList([FromBody] ReqView<MsgQueryReq> reqview)
        {
            var jwtUser = GetUseByJwtToken();

            if (jwtUser.EnterpriseId != reqview.AppId.ToString())
            {
                return await ReturnFailed(302, "当前Token和登录用户信息不匹配，请核对修改后重试");
            }

            if (reqview.Data.SessionId <= 0)
            {
                return new ResView<List<MsgQueryRes>>() { code = 500, msg = "会话ID不能为空，请修改后重试" };
            }

            var sessionDb = await DbUtils.DbHelper.GetOneAsync<MySession>(p => p.SessionId == reqview.Data.SessionId
                                && p.IsGroup == reqview.Data.IsGroup && p.BizUserId == jwtUser.BizUserID);

            if (sessionDb == null)
                return new ResView<List<MsgQueryRes>>() { code = 404, msg = "会话不存在，请重新发起聊天" };

            var msgDbItems = await DbUtils.DbHelper.GetListPageAsync<Msgs>(p => p.KID > reqview.Cursor && p.SessionId == reqview.Data.SessionId, 1, reqview.PageSize, p => p.KID, xl.webapi.db_helper_interface.OrderType.Desc);

            if (msgDbItems == null || msgDbItems.Count() == 0)
            {
                return new ResView<List<MsgQueryRes>> { code = 200, msg = "查询成功" };
            }


            var resData = new List<MsgQueryRes>();
            if (reqview.Data.IsGroup == 0)
            {
                #region 私聊 得到 发送方和接收方 去重
                var fromUserIds = msgDbItems.Select(p => p.FromBizUserId).ToList();
                var toUserIds = msgDbItems.Select(p => p.ToBizUserId).ToList();
                fromUserIds.AddRange(toUserIds);
                var allUserIds = fromUserIds.Distinct();
                var allUserDb = await DbUtils.DbHelper.GetListAsync<Users>(p => allUserIds.Contains(p.BizUserId));

                foreach (var msg in msgDbItems)
                {
                    var remsg = "";
                    if (msg.States == 1)
                        remsg = $"({allUserDb.FirstOrDefault(p => p.BizUserId == msg.ToBizUserId)?.FullName})撤回了一条消息";
                    resData.Add(new MsgQueryRes()
                    {
                        MsgId = msg.KID,
                        CreateTime = msg.CreateTime,
                        SessionId = msg.SessionId,
                        MsgType = msg.MsgType,
                        Content = msg.States == 1 ? remsg : msg.Content,
                        FromUser = allUserDb.FirstOrDefault(p => p.BizUserId == msg.FromBizUserId),
                        ToBizUserId = msg.ToBizUserId,
                        ToUser = allUserDb.FirstOrDefault(p => p.BizUserId == msg.ToBizUserId),
                        ReadTime = msg.ReadTime
                    });
                }
                #endregion
            }
            else
            {
                #region 群聊 关联 阅读时间信息
                var groupId = msgDbItems.First().ToGroupId;
                var allUserDb = await DbUtils.DbHelper.LeftJoinAsync<Users, ImGroupUser, Users>((a, b) => a.BizUserId == b.BizUserId && a.EnterpriseId == b.EnterpriseId, (a, b) => b.GroupId == groupId);

                var allMsgIds = msgDbItems.Select(p => p.KID);
                var allMsgReadDb = await DbUtils.DbHelper.GetListAsync<MsgReadTime>(p => allMsgIds.Contains(p.MsgId));

                foreach (var msg in msgDbItems)
                {
                    var remsg = "";
                    if (msg.States == 1)
                        remsg = $"({allUserDb.FirstOrDefault(p => p.BizUserId == msg.ToBizUserId)?.FullName})撤回了一条消息";
                    resData.Add(new MsgQueryRes()
                    {
                        MsgId = msg.KID,
                        CreateTime = msg.CreateTime,
                        SessionId = msg.SessionId,
                        MsgType = msg.MsgType,
                        Content = msg.States == 1 ? remsg : msg.Content,
                        FromUser = allUserDb.FirstOrDefault(p => p.BizUserId == msg.FromBizUserId),
                        //ToBizUserId = msg.ToBizUserId,
                        //ToUser = allUserDb.FirstOrDefault(p => p.BizUserId == msg.ToBizUserId),
                        //ReadTime = msg.ReadTime
                        ToGroupId = msg.ToGroupId,
                        GroupMsgRead = allMsgReadDb.Where(p => p.MsgId == msg.KID).ToList(),
                        GroupUserCnt = allMsgReadDb.Count(),
                        GroupReadCnt = allMsgReadDb.Count(p => p.MsgId == msg.KID && p.ReadTime != ""),
                    });
                }

                #endregion
            }

            return new ResView<List<MsgQueryRes>>() { code = 200, msg = "查询成功", data = resData };
        }

        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="reqview"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<ResView<Msgs>> Send([FromBody] ReqView<MsgSendView> reqview)
        {
            var jwtUser = GetUseByJwtToken();

            if (jwtUser.EnterpriseId != reqview.AppId.ToString())
            {
                return await ReturnFailed(302, "当前Token和登录用户信息不匹配，请核对修改后重试");
            }

            var bizUserId = jwtUser.BizUserID;
            var msgId = Builder.GetNewSnowId();
            var sessionId = reqview.Data.SessionId;

            ///所有用户的BizUserIds 方便后面 发消息
            var allUserBizIds = new List<string>();

            //1 查会话是否存在
            var sessionDb = await DbUtils.DbHelper.GetOneAsync<MySession>(p => p.SessionId == sessionId && p.BizUserId == bizUserId);
            if (sessionDb == null || sessionDb.SessionId <= 0)
            {
                return new ResView<Msgs>() { code = 500, msg = "发送失败，会话已不存在。" };
            }

            #region 1 写 Msg 表和 MsgReadTime
            var toBizUserId = sessionDb.IsGroup != 1 ? sessionDb.ToUserId : "";
            var toGroupId = Convert.ToInt64(sessionDb.IsGroup == 1 ? sessionDb.ToUserId : "0");
            var dayNum = Convert.ToInt32(DateTime.Now.ToString("yyyyMM"));
            var addMsgDb = await DbUtils.DbHelper.AddItemAsync<Msgs>(new Msgs()
            {
                KID = msgId,
                States = 0,
                CreateTime = DateTime.Now,
                SessionId = reqview.Data.SessionId,
                FromBizUserId = bizUserId,
                ToBizUserId = toBizUserId,
                ToGroupId = toGroupId,
                MsgType = 0,
                Content = reqview.Data.Content,
                ReadTime = "",
                DayNum = dayNum
            });

            if (addMsgDb == 0)
            {
                return new ResView<Msgs>() { code = 500, msg = "发送失败，网络超时" };
            }
            if (sessionDb.IsGroup == 1)
            {
                var ImGroupUserDb = await DbUtils.DbHelper.GetListAsync<ImGroupUser>(p => p.GroupId == toGroupId);
                allUserBizIds = ImGroupUserDb.Select(p => p.BizUserId).ToList();
                var addItems = new List<MsgReadTime>();
                foreach (var item in ImGroupUserDb)
                {
                    if (item.BizUserId == jwtUser.BizUserID)
                        continue;

                    addItems.Add(new MsgReadTime()
                    {
                        MsgId = msgId,
                        SendTime = DateTime.Now,
                        BizUserId = item.BizUserId,
                        ReadTime = ""
                    });
                }
                await DbUtils.DbHelper.AddItemsAsync<MsgReadTime>(addItems);
            }
            else
            {
                allUserBizIds.Add(sessionDb.ToUserId);
            }

            #endregion

            #region 2 写会话的未读数
            //根据会话 不等于自己的会话未读 都+1
            var upDb = await DbUtils.DbHelper.UpdateFieldsAsync<MySession>(p => new MySession()
            {
                UnReadCnt = p.UnReadCnt + 1
            }, p => p.SessionId == sessionId && p.BizUserId != bizUserId);
            #endregion

            #region 3 给 在线的 发消息
            var msgChat = new Msg_Chat
            {
                type = 0,
                sessionid = reqview.Data.SessionId,
                send = new Chat_Send()
                {
                    stype = 0,
                    content = reqview.Data.Content,
                    msgid = msgId
                }
            };

            await ImMsgLogic.SendChatMsg(reqview.AppId, msgChat, allUserBizIds, Convert.ToInt64(jwtUser.UserKid));

            var msgDb = await DbUtils.DbHelper.GetOneAsync<Msgs>(p => p.KID == msgId);
            #endregion
            return new ResView<Msgs>() { code = 200, msg = "发送成功", data = msgDb };
        }

        /// <summary>
        /// 发送系统消息 发送消息的SessionId必须和企业的ID一致
        /// </summary>
        /// <param name="reqview"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<ResView<Msgs>> SendSysMessage([FromBody] ReqView<SysMsgSendView> reqview)
        {
            var jwtUser = GetUseByJwtToken();

            if (jwtUser.EnterpriseId != reqview.AppId.ToString())
            {
                return await ReturnFailed(302, "当前Token和登录用户信息不匹配，请核对修改后重试");
            }

            var toBizUserId = reqview.Data.ToBizUserId;
            if (string.IsNullOrWhiteSpace(toBizUserId))
            {
                toBizUserId = "0";
            }
            var msgId = Builder.GetNewSnowId();
            var sessionId = reqview.AppId;

            //1 查会话是否存在
            //var sessionDb = await DbUtils.DbHelper.GetOneAsync<MySession>(p => p.SessionId == sessionId && p.BizUserId == toBizUserId);
            //if (sessionDb == null || sessionDb.SessionId <= 0)
            //{
            //    return new ResView<Msgs>() { code = 500, msg = "发送失败，会话已不存在。" };
            //}

            #region 1 写 Msg 表和 MsgReadTime
            var dayNum = Convert.ToInt32(DateTime.Now.ToString("yyyyMM"));
            var addMsgDb = await DbUtils.DbHelper.AddItemAsync<Msgs>(new Msgs()
            {
                KID = msgId,
                States = 0,
                CreateTime = DateTime.Now,
                SessionId = sessionId,
                FromBizUserId = sessionId.ToString(),
                ToBizUserId = toBizUserId,
                ToGroupId = 0,
                MsgType = 0,
                Content = reqview.Data.Content,
                ReadTime = "",
                DayNum = dayNum
            });

            if (addMsgDb == 0)
            {
                return new ResView<Msgs>() { code = 500, msg = "发送失败，网络超时" };
            }

            #endregion

            #region 2 写会话的未读数
            //根据会话
            var upDb = await DbUtils.DbHelper.UpdateFieldsAsync<MySession>(p => new MySession()
            {
                UnReadCnt = p.UnReadCnt + 1
            }, p => p.SessionId == sessionId && p.BizUserId != toBizUserId);
            #endregion

            #region 3 给 在线的 发消息
            var allUserBizIds = new List<string>();
            if (string.IsNullOrWhiteSpace(toBizUserId) || toBizUserId == "0")
            {
                allUserBizIds = (await DbUtils.DbHelper.GetListAsync<MySession>(p => p.SessionId == sessionId && p.EnterpriseId == reqview.AppId)).Select(p => p.BizUserId).ToList();
            }
            else
            {
                allUserBizIds.Add(toBizUserId);
            }
            var msgChat = new Msg_Chat
            {
                type = 0,
                sessionid = sessionId,
                send = new Chat_Send()
                {
                    stype = 0,
                    content = reqview.Data.Content,
                    msgid = msgId
                }
            };

            var senderUserDb = await DbUtils.DbHelper.GetOneAsync<Users>(p => p.BizUserId == reqview.AppId.ToString());

            await ImMsgLogic.SendChatMsg(reqview.AppId, msgChat, allUserBizIds, 0, senderUserDb);

            var msgDb = await DbUtils.DbHelper.GetOneAsync<Msgs>(p => p.KID == msgId);
            #endregion
            return new ResView<Msgs>() { code = 200, msg = "发送成功", data = msgDb };
        }

        /// <summary>
        /// 撤回消息
        /// </summary>
        /// <param name="reqview"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<ResView> ReSend([FromBody] ReqView<MsgReSendView> reqview)
        {
            var jwtUser = GetUseByJwtToken();

            if (jwtUser.EnterpriseId != reqview.AppId.ToString())
            {
                return await ReturnFailed(302, "当前Token和登录用户信息不匹配，请核对修改后重试");
            }

            var bizUserId = jwtUser.BizUserID;
            var msgId = reqview.Data.MsgId;
            var sessionId = reqview.Data.SessionId;

            var msgTime = Builder.FromSnowId(msgId);
            if (msgTime.AddMinutes(5) < DateTime.Now)
            {
                return new ResView() { code = 500, msg = "消息超过5分钟，不支持撤回。" };
            }
            var msgDayNum = Builder.FromSnowId(msgId).ToString("yyyyMM");

            var upDb = await DbUtils.DbHelper.UpdateFieldsAsync<Msgs>(p => new Msgs()
            {
                States = 1,
            }, p => p.KID == msgId && p.States == 0);

            if (upDb == 0)
            {
                return new ResView() { code = 500, msg = "消息撤回失败" };
            }


            var msgDb = await DbUtils.DbHelper.GetOneAsync<Msgs>(p => p.KID == msgId);

            var msgChat = new Msg_Chat
            {
                type = 0,
                sessionid = msgDb.SessionId,
                send = new Chat_Send()
                {
                    stype = 1,
                    content = "撤回了一条消息",
                    msgid = msgId
                }
            };

            var allUserBizIds = new List<string>();
            if (msgDb.ToGroupId > 0)
            {
                var ImGroupUserDb = await DbUtils.DbHelper.GetListAsync<ImGroupUser>(p => p.GroupId == msgDb.ToGroupId);
                allUserBizIds = ImGroupUserDb.Select(p => p.BizUserId).ToList();
            }
            else
            {
                allUserBizIds.Add(msgDb.ToBizUserId);
            }

            await ImMsgLogic.SendChatMsg(reqview.AppId, msgChat, allUserBizIds, Convert.ToInt64(jwtUser.UserKid));

            return new ResView() { code = 200, msg = "撤回成功" };
        }


        /// <summary>
        /// 已读
        /// </summary>
        /// <param name="reqview"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<ResView> Read([FromBody] ReqView<MsgReSendView> reqview)
        {
            var jwtUser = GetUseByJwtToken();

            if (jwtUser.EnterpriseId != reqview.AppId.ToString())
            {
                return await ReturnFailed(302, "当前Token和登录用户信息不匹配，请核对修改后重试");
            }

            var bizUserId = jwtUser.BizUserID;
            var msgId = reqview.Data.MsgId;
            var sessionId = reqview.Data.SessionId;

            var msgTime = Builder.FromSnowId(msgId);
            var msgDayNum = Builder.FromSnowId(msgId).ToString("yyyyMM");

            var msgDb = await DbUtils.DbHelper.GetOneAsync<Msgs>(p => p.KID == msgId);
            var readTime = DateTime.Now.ToStr();
            var upDb = 0;
            if (msgDb.SessionId == reqview.AppId)
            {
                upDb = 1;
            }
            else
            {
                if (msgDb.ToGroupId > 0)
                {
                    #region 群消息
                    upDb = await DbUtils.DbHelper.UpdateFieldsAsync<MsgReadTime>(p => new MsgReadTime()
                    {
                        ReadTime = readTime,
                    }, p => p.MsgId == msgId && p.BizUserId == jwtUser.BizUserID && p.ReadTime == "");
                    #endregion
                }
                else
                {
                    #region 私聊
                    upDb = await DbUtils.DbHelper.UpdateFieldsAsync<Msgs>(p => new Msgs()
                    {
                        ReadTime = readTime,
                    }, p => p.KID == msgId && p.ReadTime == "");
                    #endregion
                }

                if (upDb > 0)
                {
                    #region 发送已读消息
                    var chatRead = new Msg_Read()
                    {
                        type = 2,
                        sessionid = msgDb.SessionId,
                        msgid = msgId,
                        readUserId = jwtUser.BizUserID
                    };
                    await ImMsgLogic.SendReadMsg(chatRead, new List<string>() { msgDb.FromBizUserId }, Convert.ToInt64(jwtUser.UserKid));
                    #endregion
                }
            }

            #region 修改会话未读数量
            await DbUtils.DbHelper.UpdateFieldsAsync<MySession>(p => new MySession()
            {
                UnReadCnt = p.UnReadCnt > 0 ? p.UnReadCnt - 1 : 0,
            }, p => p.SessionId == sessionId && p.BizUserId == jwtUser.BizUserID);

            #endregion

            return new ResView()
            {
                code = (upDb > 0 ? 200 : 500),
                msg = (upDb > 0 ? "标记已读成功" : "标记已读失败，每条消息不支持重复设置已读")
            };
        }
    }
}
